<template>
  <div class="sights-detail user-common-bg">
    <!-- 景点信息 -->
    <div class="container">
      <div class="body">
        <div class="cover">
          <img :src="detail.cover" alt="" />
        </div>
        <div class="info">
          <div class="title">{{ detail.name }}</div>
          <div class="address">
            <i class="el-icon-map-location"></i>位置：{{ detail.address }}
          </div>
          <div class="publish-time">
            <i class="el-icon-date"></i>发布于：{{
              formatDate(detail.createTime)
            }}
          </div>
          <div class="view">
            <div class="price">
              ￥<span>{{ detail.price }}</span>
            </div>
            <div class="views">{{ detail.views }} 人浏览过</div>
            <div class="sold">已售 {{ detail.sold }}</div>
          </div>
          <div class="option">
            <el-button
              type="primary"
              icon="el-icon-edit"
              @click="dialogVisible = true"
            ></el-button>
            <el-button
              :type="detail.status === 0 ? '' : 'success'"
              :icon="
                detail.status === 0 ? 'el-icon-star-off' : 'el-icon-star-on'
              "
              @click="updateCollectStatus"
              :loading="collectLoading"
              >{{ detail.status === 0 ? "立即收藏" : "已收藏" }}</el-button
            >
            <el-button
              :type="bookingStatus === 1 ? 'success' : 'primary'"
              @click="
                bookingStatus === 1
                  ? cancelBooking()
                  : (bookingDialogVisible = true)
              "
              >{{ bookingStatus === 1 ? "已预约" : "立即预约" }}</el-button
            >
          </div>
        </div>
      </div>
      <div class="introduce">
        <div class="title">景点介绍</div>
        <div class="content" v-html="formattedText"></div>
        <p>开放时间：全天开放 🌳 🌳</p>
      </div>
    </div>
    <!-- 立即预约 -->
    <el-dialog
      title="预约"
      :visible.sync="bookingDialogVisible"
      width="60%"
      @close="bookingHandleClose"
      :close-on-click-modal="false"
      style="text-align: left"
    >
      <el-form
        :model="bookingForm"
        :rules="rules"
        label-width="100px"
        ref="bookingForm"
      >
        <el-form-item label="预约时间" prop="bookingTime">
          <el-date-picker
            v-model="bookingForm.bookingTime"
            type="date"
            placeholder="选择日期"
          >
          </el-date-picker>
        </el-form-item>
        <div
          class="dynamic-item"
          v-for="(item, index) in bookingForm.dynamicItem"
          :key="index"
        >
          <el-form-item
            class="item"
            label="游客姓名"
            :prop="'dynamicItem.' + index + '.name'"
            :rules="{
              required: true,
              message: '请输入游客姓名',
              trigger: 'blur',
            }"
          >
            <el-input
              v-model="item.name"
              :clearable="true"
              autocomplete="off"
            ></el-input>
          </el-form-item>
          <el-form-item
            class="item"
            label="联系方式"
            :prop="'dynamicItem.' + index + '.phone'"
            :rules="[
              {
                required: true,
                message: '请输入联系方式',
                trigger: 'blur',
              },
              {
                pattern: /^1[3456789]\d{9}$/,
                message: '请输入正确的手机号',
                trigger: 'blur',
              },
            ]"
          >
            <el-input
              v-model="item.phone"
              :clearable="true"
              autocomplete="off"
            ></el-input>
          </el-form-item>
          <el-form-item
            class="item"
            label="身份证号"
            :prop="'dynamicItem.' + index + '.idCard'"
            :rules="[
              {
                required: true,
                message: '请输入身份证号',
                trigger: 'blur',
              },
              {
                pattern: /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/,
                message: '请输入正确的身份证号',
                trigger: 'blur',
              },
            ]"
          >
            <el-input
              v-model="item.idCard"
              :clearable="true"
              autocomplete="off"
            ></el-input>
          </el-form-item>
          <el-form-item class="item">
            <div class="item-btn">
              <i
                class="el-icon-circle-plus-outline"
                style="color: #409eff"
                v-if="index + 1 == bookingForm.dynamicItem.length"
                @click="addItem"
              ></i>
              <i
                class="el-icon-remove-outline"
                style="color: #f56c6c"
                v-if="index !== 0"
                @click="deleteItem(index)"
              ></i>
            </div>
          </el-form-item>
        </div>
      </el-form>
      <span slot="footer">
        <el-button @click="bookingDialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="addBooking" :loading="bookingLoading"
          >确 定</el-button
        >
      </span>
    </el-dialog>
    <!-- 景点评论 -->
    <div class="remark">
      <RemarkView
        :remarkListLoading="remarkListLoading"
        :remarkList="dataList"
        :total="total"
        @getRemarkList="getRemarkList"
      ></RemarkView>
      <!-- 分页 -->
      <el-pagination
        v-show="dataList.length > 0"
        background
        layout="prev, pager, next"
        :total="total"
        :current-page="currentPage"
        :page-size="pageSize"
        @current-change="handleCurrentChange"
        :page-count="7"
        style="text-align: right; margin-top: 24px"
      >
      </el-pagination>
    </div>
    <!-- 写评论 -->
    <el-dialog
      title="写评论"
      :visible.sync="dialogVisible"
      width="56%"
      @close="handleClose"
      :close-on-click-modal="false"
    >
      <div class="editor-container">
        <Toolbar
          style="border-bottom: 1px solid #ccc"
          :editor="editor"
          :defaultConfig="toolbarConfig"
          :mode="mode"
        />
        <Editor
          style="height: 210px; overflow-y: hidden"
          v-model="html"
          :defaultConfig="editorConfig"
          :mode="mode"
          @onCreated="onCreated"
        />
      </div>
      <span slot="footer">
        <el-button @click="dialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="addRemark" :loading="insertLoading"
          >确 定</el-button
        >
      </span>
    </el-dialog>
  </div>
</template>

<script>
import RemarkView from "@/components/RemarkView.vue";
import { Editor, Toolbar } from "@wangeditor/editor-for-vue";
import { updateSightsCollectStatus } from "@/api/user/collect";
import { getSightsDetail } from "@/api/user/sights";
import { addRemark, getRemarkList } from "@/api/user/remark";
import userModule from "@/utils/userInfo";
import {
  addSightsBooking,
  cancelSightsBooking,
  getSightsBooking,
} from "@/api/user/booking";

export default {
  name: "SightsDetail",
  props: ["id"],
  computed: {
    formattedText() {
      // 将换行符替换为带有缩进的换行符
      return this.detail.introduce.replace(
        /\n/g,
        '<br style="display: block; margin-top: 1em"><span style="display: inline-block; width: 2em"></span>'
      );
    },
  },
  components: {
    RemarkView,
    Editor,
    Toolbar,
  },
  data() {
    return {
      detail: {
        // 不赋初值在computed中会报undefined调用replace方法
        introduce: "",
      },
      collectLoading: false,
      insertLoading: false,
      detailLoading: false,
      bookingLoading: false,
      remarkListLoading: false,
      bookingDialogVisible: false,
      dialogVisible: false,
      dataList: [],
      // 预约表单信息
      bookingForm: {
        bookingTime: "",
        dynamicItem: [
          // 默认显示一条
          {
            name: "",
            phone: "",
            idCard: "",
          },
        ],
      },
      rules: {
        bookingTime: [
          { required: true, message: "请选择预约时间", trigger: "blur" },
          // 自定义规则
          {
            validator: (rule, value, callback) => {
              const now = new Date().getTime();
              const oneDayInMillisecods = 24 * 60 * 60 * 1000;
              const previousDayTimestamp = now - oneDayInMillisecods;
              const lastDate = new Date(previousDayTimestamp);

              const selectedDate = new Date(value);
              if (selectedDate < lastDate) {
                callback(new Error("不能为今天以前的时间"));
              } else {
                callback();
              }
            },
            trigger: "blur",
          },
        ],
      },
      bookingStatus: 0,
      bookingId: "",
      page: 1,
      pageSize: 10,
      total: 0,
      currentPage: 1,
      // 富文本框配置
      editor: null,
      html: "",
      toolbarConfig: {
        // 排除菜单中的上传图片和上传视频功能
        excludeKeys: ["group-image", "insertVideo"],
      },
      editorConfig: {
        placeholder: "请输入内容...",
        MENU_CONF: {},
      },
      mode: "simple", // or 'simple'
    };
  },
  created() {
    this.getSightsBooking();
    this.getSightsDetail();
    this.getRemarkList();
  },
  beforeDestroy() {
    const editor = this.editor;
    if (editor == null) return;
    editor.destroy(); // 组件销毁时，及时销毁编辑器
  },
  methods: {
    // 获取景点详情
    async getSightsDetail() {
      try {
        this.detailLoading = true;
        const res = await getSightsDetail({ id: this.id });
        this.detail = res.data;
      } finally {
        this.detailLoading = false;
      }
    },
    // 添加评论
    async addRemark() {
      const content = this.html;
      if (content === "") {
        this.$message.warning("请输入评论内容");
        return;
      }
      try {
        this.insertLoading = true;
        const res = await addRemark({
          userId: userModule.getUser().id,
          type: "sights",
          typeId: this.id,
          content,
        });
        this.dialogVisible = false;
        this.getRemarkList();
      } finally {
        this.insertLoading = false;
      }
    },
    // 获取评论列表
    async getRemarkList() {
      try {
        this.remarkListLoading = true;
        const res = await getRemarkList({
          page: this.page,
          pageSize: this.pageSize,
          type: "sights",
          typeId: this.id,
        });
        this.dataList = res.data.records;
        this.total = res.data.total;
      } catch {
        this.$message.error("获取评论列表失败");
      } finally {
        this.remarkListLoading = false;
      }
    },
    // 收藏
    async updateCollectStatus() {
      try {
        this.collectLoading = true;
        const res = await updateSightsCollectStatus({
          id: this.id,
          status: this.detail.status === 0 ? 1 : 0,
        });
        this.getSightsDetail();
        this.$notify.success({
          message: "操作成功",
        });
      } catch {
        this.$notify.error({
          message: "操作失败",
        });
      } finally {
        this.collectLoading = false;
      }
    },
    // 查询预约情况
    async getSightsBooking() {
      const res = await getSightsBooking({
        userId: userModule.getUser().id,
        sightsId: this.id,
      });
      this.bookingId = res.data.id;
      this.bookingStatus = res.data.status;
    },
    // 立即预约
    addBooking() {
      this.$refs.bookingForm.validate(async (v) => {
        if (v) {
          try {
            this.bookingLoading = true;
            const res = await addSightsBooking({
              userId: userModule.getUser().id,
              sightsId: this.id,
              bookingTime: this.bookingForm.bookingTime,
              bookingPersonList: this.bookingForm.dynamicItem,
            });
            this.getSightsBooking();
            this.bookingDialogVisible = false;
          } catch {
            this.$message.error("预约失败");
          } finally {
            this.bookingLoading = false;
          }
        }
      });
    },
    // 取消预约
    async cancelBooking() {
      try {
        this.bookingLoading = true;
        const res = await cancelSightsBooking({
          sightsId: this.id,
          userId: userModule.getUser().id,
          bookingId: +this.bookingId,
        });
        this.getSightsBooking();
      } finally {
        this.bookingLoading = false;
      }
    },
    // 预约人员新增
    addItem() {
      this.bookingForm.dynamicItem.push({
        name: "",
        phone: "",
        idCard: "",
      });
    },
    // 预约人员删除
    deleteItem(index) {
      this.bookingForm.dynamicItem.splice(index, 1);
    },
    // 分页
    handleCurrentChange(page) {
      this.page = page;
      this.currentPage = page;
      this.getRemarkList();
    },
    // 时间格式判断
    padZero(num) {
      return num < 10 ? "0" + num : num;
    },
    // 时间格式化
    formatDate(timeArray) {
      if (!timeArray) return "暂无时间";
      let year = timeArray[0];
      let month = this.padZero(timeArray[1]);
      let day = this.padZero(timeArray[2]);
      let hour = this.padZero(timeArray[3]);
      let minute = this.padZero(timeArray[4]);
      let second = this.padZero(timeArray[5]) || "00";
      return `${year}-${month}-${day} ${hour}:${minute}:${second}`;
    },
    // 关闭对话框
    handleClose() {
      this.html = "";
    },
    // 关闭预约对话框
    bookingHandleClose() {
      this.$refs.bookingForm.resetFields();
      this.bookingForm.dynamicItem = [
        // 默认显示一条
        {
          name: "",
          phone: "",
          idCard: "",
        },
      ];
    },
    // 富文本框配置
    onCreated(editor) {
      this.editor = Object.seal(editor); // 一定要用 Object.seal() ，否则会报错
    },
  },
};
</script>

<style lang="less" scoped>
.sights-detail {
  padding: 0 100px;
  .container {
    margin-top: 100px;
    width: 100%;
    min-height: 300px;
    border-radius: 8px;
    box-shadow: 0 0 10px rgba(0, 0, 0, 0.16);
    .body {
      display: flex;
      .cover {
        width: 60%;
        height: 360px;
        border-top-left-radius: 8px;
        border-bottom-right-radius: 8px;
        img {
          width: 100%;
          height: 100%;
          border-top-left-radius: 8px;
          border-bottom-right-radius: 8px;
        }
      }
      .info {
        width: 40%;
        padding-top: 10px;
        padding-left: 10px;
        padding-right: 10px;
        text-align: left;
        .title {
          font-size: 30px;
          font-weight: bold;
        }
        .address {
          margin: 8px 0;
          font-size: 15px;
          color: #999;
        }
        .publish-time {
          margin: 8px 0;
          font-size: 15px;
          color: #999;
        }
        .view {
          display: flex;
          align-items: flex-end;
          width: 80%;
          .price {
            color: rgb(255, 138, 61);
            font-size: 40px;
            span {
              font-size: 30px;
              font-weight: 600;
            }
          }
          .views {
            margin-left: 10px;
            line-height: 2.1;
            font-size: 15px;
            color: #999;
          }
          .sold {
            margin-left: 10px;
            line-height: 2.1;
            font-size: 15px;
            color: #999;
          }
        }
        .option {
          display: flex;
          justify-content: flex-end;
          align-items: flex-end;
          width: 96%;
          height: 190px;
        }
      }
    }
    .introduce {
      padding: 10px 20px;
      text-align: left;
      .title {
        margin: 10px 0;
        font-size: 20px;
        font-weight: bold;
      }
      .content {
        display: inline-block;
        font-size: 15px;
        line-height: 1.6;
        text-indent: 2em;
        color: #666;
        white-space: pre-wrap;
      }
      p {
        height: 40px;
        line-height: 40px;
        font-size: 14px;
        font-weight: 600;
      }
    }
  }
  .remark {
    margin: 10px 0;
    padding-block: 10px;
    min-height: 300px;
    border-radius: 8px;
    box-shadow: 0 0 8px rgba(0, 0, 0, 0.15);
  }
  .editor-container {
    text-align: left;
    height: 300px;
    border: 1px solid;
  }
}
.dynamic-item {
  display: flex;
  height: 60px;
  .item {
    width: 400px;
    height: 100%;
    &:nth-of-type(4) {
      position: relative;
      width: 50px;
    }
  }
  .item-btn {
    position: absolute;
    left: -94px;
    top: 10px;
    display: flex;
    justify-content: space-between;
    width: 46px;
    i {
      font-size: 18px;
      font-weight: 600;
      cursor: pointer;
    }
  }
}
</style>